﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace LC_AsyncDelegate.BeginInvoke
{
    /// <summary>
    /// 对于异步调用，.NET内部究竟做了什么？
    /// 一旦你使用.NET完成了一次异步调用，它都需要一个线程来处理异步工作内容(以下简称异步线程)，异步线程不可能是当前的调用线程，因为那样仍然会造成调用线程的阻塞，与同步无异。事实上，.NET会将所有的异步请求队列加入线程池，以线程池内的线程处理所有的异步请求。对于线程池似乎不必了解的过于深入，但我们仍需要关注以下几点内容：
    /// ●  SleepOneSecond0()的异步调用会在一个单独的线程内执行，这个线程来自于.NET线程池。
    /// ●  .NET线程池默认包含25个线程（具体数量根据操作系统这些决定），你可以改变这个值的上限，每次异步调用都会使用其中某个线程执行，但我们并不能控制具体使用哪一个线程。
    /// ●  线程池具备最大线程数目上限，一旦所有的线程都处于忙碌状态，那么新的异步调用将会被置于等待队列，直到线程池产生了新的可用线程，因此对于大量异步请 求，我们有必要关注请求数量，否则可能造成性能上的影响。
    /// 
    /// ------------------------------------------------------------------------------------------------------
    /// 
    /// 对于输出结果，我们可以总结为以下内容：
    /// ●  所有的异步线程都来自于.NET线程池。
    /// ●  每次执行一次异步调用，便产生一个新的线程；同时可用线程数目减少。
    /// ●  在执行异步调用n次后，当线程池线程被占用完后，线程池中不再有空闲线程。此时，应用程序会等待空闲线程的产生。
    /// ●  一旦线程池内产生了空闲线程，它会立即被分配给异步任务等待队列，之后线程池中仍然不具备空闲线程，应用程序主线程进入挂起状态继续等待空闲线程，这样的调用一直持续到异步调用被执行完n次。(n指的是调用次数)
    /// ●  针对以上结果，我们对于异步调用可以总结为以下内容：
    /// ●  每次异步调用都在新的线程中执行，这个线程来自于.NET线程池。
    /// ●  线程池有自己的执行上限，如果你想要执行多次耗费时间较长的异步调用，那么线程池有可能进入一种”线程饥饿”状态，去等待可用线程的产生。
    /// </summary>
    public class BeginInvokeClass
    {
        public static void UsingEndInvoke0()
        {
            ThreadMethod.PrintInfo("UsingEndInvoke0");

            // 创建包含Sleep函数的委托对象
            Action invoker = new Action(SleepOneSecond0);
            for (int i = 0; i < 30; i++)
            {
                // 以异步的形式，调用Sleep函数30次--使用线程池线程，而非主线程
                invoker.BeginInvoke(null, null);
            }
        }
        public static void SleepOneSecond0()
        {
            ThreadMethod.PrintInfo("SleepOneSecond0");

            Thread.Sleep(60000);//休眠时间越小，线程释放速度越快，反之释放速度越慢。----------可以试试3000和60000比较结果
        }
    }
}
